/**
* Copyright (c) 2005-2011 by Appcelerator, Inc. All Rights Reserved.
* Licensed under the terms of the Eclipse Public License (EPL).
* Please see the license.txt included with this distribution for details.
* Any modifications to this file must keep this entire header intact.
*/
package com.python.pydev.analysis.indexview;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.HashSet;
import java.util.Iterator;
import java.util.List;
import java.util.Set;
import java.util.TreeSet;
import org.eclipse.core.resources.IProject;
import org.eclipse.core.runtime.NullProgressMonitor;
import org.python.pydev.core.ICodeCompletionASTManager;
import org.python.pydev.core.IModulesManager;
import org.python.pydev.core.IPythonNature;
import org.python.pydev.core.MisconfigurationException;
import org.python.pydev.core.ModulesKey;
import org.python.pydev.core.docutils.StringUtils;
import org.python.pydev.editor.codecompletion.revisited.PythonPathHelper;
import org.python.pydev.editor.codecompletion.revisited.modules.AbstractModule;
import org.python.pydev.editor.codecompletion.revisited.modules.SourceModule;
import org.python.pydev.parser.visitors.scope.ASTEntry;
import org.python.pydev.plugin.nature.PythonNature;
import org.python.pydev.utils.PyFileListing.PyFileInfo;
import com.aptana.shared_core.io.FileUtils;
import com.aptana.shared_core.structure.Tuple;
import com.python.pydev.analysis.additionalinfo.AbstractAdditionalDependencyInfo;
import com.python.pydev.analysis.additionalinfo.AbstractAdditionalTokensInfo;
import com.python.pydev.analysis.additionalinfo.AdditionalProjectInterpreterInfo;
public class NatureGroup extends ElementWithChildren {
public static class IntegrityInfo {
public IPythonNature nature;
public List<ModulesKey> modulesNotInDisk = new ArrayList<ModulesKey>();
public List<ModulesKey> modulesNotInMemory = new ArrayList<ModulesKey>();
public List<SourceModule> moduleNotInAdditionalInfo = new ArrayList<SourceModule>();
public List<String> additionalModulesNotInDisk = new ArrayList<String>();
}
private PythonNature nature;
public NatureGroup(ITreeElement parent, PythonNature nature) {
super(parent);
this.nature = nature;
}
public boolean hasChildren() {
return true;
}
@Override
protected void calculateChildren() throws MisconfigurationException {
ICodeCompletionASTManager astManager = nature.getAstManager();
if (astManager == null) {
addLeaf("AST manager == null (should happen only in the plugin initialization) -- skipping other checks.");
return;
}
IModulesManager projectModulesManager = astManager.getModulesManager();
if (projectModulesManager == null) {
addLeaf("Modules manager == null (should happen only in the plugin initialization) -- skipping other checks.");
return;
}
PythonPathHelper pythonPathHelper = (PythonPathHelper) projectModulesManager.getPythonPathHelper();
if (pythonPathHelper == null) {
addLeaf("PythonPathHelper == null (should happen only in the plugin initialization) -- skipping other checks.");
return;
}
List<String> pythonpath = pythonPathHelper.getPythonpath();
for (String s : pythonpath) {
addLeaf("PYTHONPATH: " + s);
}
HashSet<ModulesKey> expectedModuleNames = new HashSet<ModulesKey>();
for (String string : pythonpath) {
File file = new File(string);
if (file.isDirectory()) { //TODO: Handle zip file modules!
Collection<PyFileInfo> modulesBelow = pythonPathHelper.getModulesBelow(file, new NullProgressMonitor())
.getFoundPyFileInfos();
for (PyFileInfo fileInfo : modulesBelow) {
File moduleFile = fileInfo.getFile();
String modName = pythonPathHelper.resolveModule(FileUtils.getFileAbsolutePath(moduleFile), true);
if (modName != null) {
expectedModuleNames.add(new ModulesKey(modName, moduleFile));
} else {
if (PythonPathHelper.isValidModuleLastPart(StringUtils.stripExtension((moduleFile.getName())))) {
addLeaf(com.aptana.shared_core.string.StringUtils.format("Unable to resolve module: %s (gotten null module name)",
moduleFile));
}
}
}
} else {
if (!file.exists()) {
addLeaf(com.aptana.shared_core.string.StringUtils.format("File %s is referenced in the pythonpath but does not exist.", file));
} else {
addLeaf(com.aptana.shared_core.string.StringUtils
.format("File %s not handled (TODO: Fix zip files support in the viewer).", file));
}
}
}
IntegrityInfo info = new IntegrityInfo();
info.nature = nature;
ModulesKey[] onlyDirectModules = projectModulesManager.getOnlyDirectModules();
TreeSet<ModulesKey> inModulesManager = new TreeSet<ModulesKey>(Arrays.asList(onlyDirectModules));
Set<String> allAdditionalInfoModuleNames = new TreeSet<String>();
List<Tuple<AbstractAdditionalTokensInfo, IPythonNature>> additionalInfoAndNature = AdditionalProjectInterpreterInfo
.getAdditionalInfoAndNature(nature, false, false, false);
AbstractAdditionalTokensInfo additionalProjectInfo;
if (additionalInfoAndNature.size() == 0) {
addChild(new LeafElement(this, "No additional infos found (1 expected) -- skipping other checks."));
return;
} else {
if (additionalInfoAndNature.size() > 1) {
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format(
"%s additional infos found (only 1 expected) -- continuing checks but analysis may be wrong.",
additionalInfoAndNature.size())));
}
additionalProjectInfo = additionalInfoAndNature.get(0).o1;
allAdditionalInfoModuleNames.addAll(additionalProjectInfo.getAllModulesWithTokens());
}
for (ModulesKey key : inModulesManager) {
if (!expectedModuleNames.contains(key)) {
info.modulesNotInDisk.add(key);
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format("%s exists in memory but not in the disk.", key)));
}
}
ModulesKey tempKey = new ModulesKey(null, null);
for (String s : allAdditionalInfoModuleNames) {
tempKey.name = s;
if (!expectedModuleNames.contains(tempKey)) {
info.additionalModulesNotInDisk.add(s);
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format(
"%s exists in the additional info but not in the disk.", s)));
}
}
for (ModulesKey key : expectedModuleNames) {
boolean isInModulesManager = inModulesManager.contains(key);
if (!isInModulesManager) {
info.modulesNotInMemory.add(key);
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format("%s exists in the disk but not in memory.", key)));
}
if (!allAdditionalInfoModuleNames.contains(key.name)) {
try {
AbstractModule mod = AbstractModule.createModule(key.name, key.file, info.nature, true);
if (!(mod instanceof SourceModule)) {
continue;
}
SourceModule module = (SourceModule) mod;
if (module == null || module.getAst() == null) {
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format(
"Warning: cannot parse: %s - %s (so, it's ok not having additional info on it)",
key.name, key.file)));
} else {
try {
Iterator<ASTEntry> innerEntriesForAST = AbstractAdditionalDependencyInfo
.getInnerEntriesForAST(module.getAst()).o2;
if (innerEntriesForAST.hasNext()) {
info.moduleNotInAdditionalInfo.add(module);
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format(
"The additional info index of the module: %s is not updated.", key.name)));
}
} catch (Exception e) {
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format(
"Unexpected error happened on: %s - %s: %s", key.name, key.file, e.getMessage())));
}
}
} catch (IOException e) {
//OK, it cannot be parsed, so, we cannot generate its info
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format(
"Warning: cannot parse: %s - %s (so, it's ok not having additional info on it)", key.name,
key.file)));
}
}
}
//modules manager
if (info.modulesNotInDisk.size() > 0) {
for (ModulesKey m : info.modulesNotInDisk) {
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format("FIX: Removing from modules manager: %s", m)));
}
projectModulesManager.removeModules(info.modulesNotInDisk);
}
for (ModulesKey key : info.modulesNotInMemory) {
addChild(new LeafElement(this, "FIX: Adding to modules manager: " + key));
projectModulesManager.addModule(key);
}
//additional info
for (String s : info.additionalModulesNotInDisk) {
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format("FIX: Removing from additional info: %s", s)));
additionalProjectInfo.removeInfoFromModule(s, true);
}
for (SourceModule mod : info.moduleNotInAdditionalInfo) {
addChild(new LeafElement(this, com.aptana.shared_core.string.StringUtils.format("FIX: Adding to additional info: %s", mod.getName())));
additionalProjectInfo.addAstInfo(mod.getAst(), mod.getModulesKey(), true);
}
}
private void addLeaf(String msg) {
addChild(new LeafElement(this, msg));
}
@Override
public String toString() {
IProject project = nature.getProject();
if (project != null) {
return project.getName();
}
return "Project not set";
}
}